﻿using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using AzukiMap.Element;
using AzukiMap.Map;
using GeoAPI.Geometries;
using GisSharpBlog.NetTopologySuite.Geometries;
using Label=AzukiMap.Element.Label;

namespace AzukiMap.Layer
{
    public class LabelLayer : Canvas
    {
        private const string DEFAULT_FONT = "Arial";
        private const double DEFAULT_FONTSIZE = 10.5;
        private readonly List<IEnvelope> _labelExtents;
        private readonly MapCoordinate _mapCoord;
        private readonly Color DEFAULT_BGCOLOR = Colors.White;
        private readonly Color DEFAULT_COLOR = Colors.Black;

        private Canvas _layerContainer;

        public LabelLayer(Canvas layerContainer, MapCoordinate mapCoord)
        {
            _mapCoord = mapCoord;
            _layerContainer = layerContainer;
            _labelExtents = new List<IEnvelope>();

            LabelFont = new FontFamily(DEFAULT_FONT);
            LabelBrush = new SolidColorBrush(DEFAULT_COLOR);
            LabelSize = DEFAULT_FONTSIZE;
            NeedsBackground = true;
            BackgroundBrush = new SolidColorBrush(DEFAULT_BGCOLOR);

            SetValue(ZIndexProperty, 1000);
            layerContainer.Children.Add(this);
        }

        public FontFamily LabelFont { get; set; }

        public Brush LabelBrush { get; set; }

        public double LabelSize { get; set; }

        public bool NeedsBackground { get; set; }

        public Brush BackgroundBrush { get; set; }

        public TextBlock Add(Label label)
        {
            if (label.Geom.IsEmpty)
            {
                return null;
            }
            IPoint labelPoint = label.Geom.Centroid;
            IPoint pixPoint = _mapCoord.GetPixPointFromGeo(labelPoint);
            var labelElement
                = new TextBlock
                      {
                          Text = label.Text,
                          FontSize = label.FontSize,
                          FontFamily = label.Font,
                          FontWeight = label.FontWeight,
                          Foreground = label.Foreground,
                          HorizontalAlignment = label.HorizontalAlignment,
                          VerticalAlignment = label.VerticalAlignment,
                          Margin = label.Margin
                      };

            ICoordinate tl = new Coordinate(
                pixPoint.X - labelElement.ActualWidth / 2,
                pixPoint.Y - labelElement.ActualHeight / 2
                );
            ICoordinate br = new Coordinate(
                pixPoint.X + labelElement.ActualWidth / 2,
                pixPoint.Y + labelElement.ActualHeight / 2
                );
            IEnvelope extent = new Envelope(tl, br);

            bool hasOverlaps = false;
            foreach (IEnvelope labelExtent in _labelExtents)
            {
                if (extent.Overlaps(labelExtent))
                {
                    hasOverlaps = true;
                    break;
                }
            }
            if (!hasOverlaps)
            {
                /*
                DropShadowEffect whiteBack = new DropShadowEffect();
                whiteBack.BlurRadius = 5;
                whiteBack.Color = Colors.White;
                whiteBack.Direction = 0;
                whiteBack.ShadowDepth = 0;
                labelElement.Effect = whiteBack;
                 */

                if (label.NeedsBackground)
                {
                    var labelBackElement
                        = new TextBlock
                              {
                                  Text = label.Text,
                                  FontFamily = label.Font,
                                  FontSize = label.FontSize,
                                  Foreground = label.Background,
                                  FontWeight = label.BackgroundFontWeight,
                                  HorizontalAlignment = label.HorizontalAlignment,
                                  VerticalAlignment = label.VerticalAlignment,
                                  Margin = label.Margin
                              };

                    labelBackElement.SetValue(LeftProperty, tl.X + label.BackgroundOffsetX);
                    labelBackElement.SetValue(TopProperty, tl.Y + label.BackgroundOffsetY);

                    Children.Add(labelBackElement);
                }

                labelElement.SetValue(LeftProperty, tl.X);
                labelElement.SetValue(TopProperty, tl.Y);

                Children.Add(labelElement);
                _labelExtents.Add(extent);

                return labelElement;
            }

            return null;
        }

        public void Clear()
        {
            Children.Clear();
            _labelExtents.Clear();
        }

        public void Show()
        {
            Visibility = Visibility.Visible;
        }

        public void Hide()
        {
            Visibility = Visibility.Collapsed;
        }
    }
}